import datetime
import math
import uuid
from time import sleep
import time

import pinyin
import selenium.webdriver.support.expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

from utils.CommonEnum import HourEnum, MinuteEnum


class ObjDictTool:

    @staticmethod
    def to_dic(obj):
        '''
        实体转字典
        :param obj: 待转换的实体类
        :return: 字典
        '''
        dic = {}
        for fieldkey in dir(obj):
            fieldvaule = getattr(obj, fieldkey)
            if fieldvaule is not None and not fieldkey.startswith("__") and not callable(
                    fieldvaule) and not fieldkey.startswith("_"):
                dic[fieldkey] = fieldvaule
        return dic

    @staticmethod
    def to_obj(obj: object, **data):
        '''
        将字典转实体类
        :param obj: 实体类（输出）
        :param data: 字典（输入）
        :return:
        '''
        obj.__dict__.update(data)

    @staticmethod
    def copyA2B(a, b):
        '''
        把a对象的值copy到b对象
        :param a: 源值
        :param b: 目标值
        :return:
        '''
        if not a:
            return
        for key in dir(a):  # 遍历数据字典
            if 'id' == key:
                continue
            if 'query' == key:
                continue
            if 'metadata' == key:
                continue
            if key.startswith('_'):
                continue
            if hasattr(b, key):  # 如果存在同名属性
                setattr(b, key, getattr(a, key))  # 则添加属性到对象中

    @staticmethod
    def chunks(arr, m):
        n = int(math.ceil(len(arr) / float(m)))
        return [arr[i:i + n] for i in range(0, len(arr), n)]


class PinyinTool:
    '''
    拼音工具
    '''

    @staticmethod
    def getPinyinAbridge(stock_name):
        '''
        汉字拼音首字母缩写
        :param string:
        :return:
        '''
        return pinyin.get_initial(stock_name, delimiter="")


class SpiderTool:
    '''
    爬虫工具类
    '''

    @staticmethod
    def isElementPresent(driver, by, value):
        """
        用来判断元素标签是否有下一页，
        """
        try:

            element = driver.find_element(by=by, value=value)
        except NoSuchElementException as e:
            # 发生了NoSuchElementException异常，说明页面中未找到该元素，返回False
            return False
        else:
            # 没有发生异常，表示在页面中找到了该元素，返回True
            return True

    @staticmethod
    def pageDown(bro):
        wait = WebDriverWait(bro, 2)
        wait.until(
            lambda driver: driver.find_element_by_link_text('下一页'))  # 内容加载完成后爬取
        next_page = bro.find_element_by_link_text('下一页')
        next_page.click()  # 模拟点击下一页
        sleep(5)

    # 一直等待某元素可见，默认超时10秒
    @staticmethod
    def is_visible(driver, locator, by=By.XPATH, timeout=10):
        try:
            WebDriverWait(driver, timeout).until(EC.visibility_of_element_located((by, locator)))
            return True
        except TimeoutException:
            return False

    @staticmethod
    def get_value(driver, locator, by=By.XPATH, timeout=10):
        count = 0
        val = ''
        while True:
            try:
                WebDriverWait(driver, timeout).until(EC.visibility_of_element_located((by, locator)))
                val = driver.find_element(by, value=locator).text
                break
            except:
                if count >= 3:
                    break
                sleep(2)
                ++count
        return val

    # 一直等待某个元素消失，默认超时10秒
    @staticmethod
    def is_not_visible(driver, locator, timeout=10):
        try:
            WebDriverWait(driver, timeout).until_not(EC.visibility_of_element_located((By.XPATH, locator)))
            return True
        except TimeoutException:
            return False


class CalculationTool:
    '''
    计算股票工具栏
    '''

    @staticmethod
    def calculateChg(cur, pre):
        '''
        计算涨跌幅
        :param cur: 当前价
        :param pre: 前值
        :return: 涨跌幅度  %
        '''
        if cur and pre:
            return round((cur - pre) / pre * 100, 2)
        return 0

    @staticmethod
    def cutOutTail(funds):
        '''
        截取尾巴
        :param funds:
        :return:
        '''
        if funds:
            if (funds.rfind('亿') != -1):
                funds = funds.replace('亿', '')
            if (funds.rfind('万') != -1):
                funds = funds.replace('万', '')
            if (funds.rfind('%') != -1):
                funds = funds.replace('%', '')
            if funds.rfind('手') != -1:
                funds = funds.replace('手', '')

        return funds

    @staticmethod
    def convert2W(funds):
        '''
        亿->万
        :param funds:
        :return:
        '''
        if funds:
            if funds.rfind('元'):
                funds = funds.replace('元', '')

            if (funds.rfind('万') != -1):
                return funds.replace('万', '')
            elif (funds.rfind('亿') != -1):
                return float(funds.replace('亿', '')) * 4
            elif (funds == '-'):
                return 0
            else:
                return funds
        return 0

    @staticmethod
    def convert2Y(funds):
        '''
        万->亿
        :param funds:
        :return:
        '''
        if funds:
            if (funds.rfind('亿') != -1):
                return funds.replace('亿', '')
            elif (funds.rfind('万') != -1):
                return round(float(funds.replace('万', '')) / 1e4, 3)
            elif funds == '-':
                return 0
            else:
                return funds
        return 0

    @staticmethod
    def str_of_num(num):
        '''
        递归实现，精确为最大单位值 + 小数点后三位
        '''

        def strofsize(num, level):
            if level >= 2:
                return num, level
            elif num >= 10000:
                num /= 10000
                level += 1
                return strofsize(num, level)
            else:
                return num, level

        units = ['', '万', '亿']
        num, level = strofsize(num, 0)
        if level > len(units):
            level -= 1
        return '{}{}'.format(round(num, 3), units[level])


class StockTool():
    market = {'60': 'sh', '68': 'sh', '00': 'sz', '30': 'sz'}
    marketNum = {'60': '1', '68': '1', '00': '0', '30': '0'}

    @staticmethod
    def code2Market(code):
        '''
        根据股票代码分清哪个市场
        :param code:
        :return:
        '''
        return StockTool.market.get(code[0:2])

    @staticmethod
    def code2MarketNum(code):
        '''
        根据股票代码分清哪个市场
        :param code:
        :return:
        '''
        return StockTool.marketNum.get(code[0:2])


class FlaskTool():

    @staticmethod
    def modelList(result):
        list = []
        for row in result:
            dict = {}
            for k, v in row.__dict__.items():
                if not k.startswith('_sa_instance_state'):
                    dict[k] = v
            list.append(dict)

        return list

    @staticmethod
    def paginatioToList(pagination):
        dict = {}
        items = pagination.items
        dict['rows'] = FlaskTool.modelList(items)
        dict['total'] = pagination.total
        return dict

    @staticmethod
    def customPaginatio(list, total):
        '''
        自定义分页
        :param pagination:
        :return:
        '''
        dict = {}
        dict['rows'] = FlaskTool.modelList(list)
        dict['total'] = total
        return dict

    @staticmethod
    def propertyGrid(result):
        dict = {}
        dict['rows'] = FlaskTool.modelList(result)
        dict['total'] = len(result)
        return dict


class CommonUtil:
    @staticmethod
    def timestamp2Date(time_stamp):
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time_stamp))

    @staticmethod
    def timeIninterval(now_time=time.strftime("%H:%M:%S", time.localtime()), start_time='09:30:00',
                       end_time='11:31:00'):
        return start_time <= now_time <= end_time

    @staticmethod
    def optimizeStr(str):
        '''
        去除字符串换行符和空格
        :param str:
        :return:
        '''
        if str:
            return str.replace('\n', '').strip()
        else:
            return ''

    @staticmethod
    def str2date(datestr):
        '''
        03月25日 18:32
        :param str:
        :return:
        '''
        if datestr:
            year = datetime.datetime.now().year
            datestr = str(year) + '年' + CommonUtil.optimizeStr(datestr)
            return datetime.datetime.strptime(datestr, '%Y年%m月%d日 %H:%M')
        else:
            return datetime.datetime.now()

    @staticmethod
    def get_time_interval(hour, minute):
        hour_str = HourEnum.getval(hour)
        if not hour_str:
            return None
        minute_str = MinuteEnum.getval(minute)
        if not minute_str:
            return None
        return hour_str + minute_str

    @staticmethod
    def get_uuid():
        return uuid.uuid4()
